/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cs575.coresystem;

import cs575.dbentities.Converter;
import cs575.dbentities.TaskAssign;
import cs575.dbentities.GroupEx;
import cs575.dbentities.GroupMember;
import cs575.dbentities.GroupMemberPK;
import cs575.dbentities.User;
import cs575.dbentities.GroupInvitation;
import cs575.dbentities.GroupInvitationPK;
import cs575.dbentities.IGroupRole;
import cs575.dbentities.Role;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

/**
 *
 * @author bms
 */
public class GroupManager {
    private EntityManager em;

    public GroupManager() {
        
    }
      
    public GroupManager(EntityManager em) {
        this.em = em;
    }
    
    public GroupEx retrieveGroup(int groupId) {
            GroupEx GroupEx = em.find(GroupEx.class, groupId);
            return GroupEx;
    }    

    public GroupEx createGroup(String groupName, String groupDescription, User user) {
        GroupEx result = null;
        EntityTransaction GroupTransaction = em.getTransaction();
        try{
            GroupTransaction.begin();
            GroupEx paramGroup = new GroupEx(groupName, groupDescription);
            if (paramGroup != null) {
                em.persist(paramGroup);
                GroupMember member = addUserToGroup(user, paramGroup, new Role(Role.Admin));
                if (member != null) {
                    result = paramGroup;
                }
            }
        }finally{
            if(result!=null)
                GroupTransaction.commit();
            else
                GroupTransaction.rollback();
        }
        return result;
    }
    
      public GroupEx createGroupReference(int groupId) {
            GroupEx GroupEx = em.getReference(GroupEx.class, groupId);
            return GroupEx;
    }  
            
    public boolean storeGroup(GroupEx newGroup) {
        boolean result = false;
        EntityTransaction GroupTransaction = em.getTransaction();
        try {
            GroupTransaction.begin();
            em.persist(newGroup);
            result = true;
        } finally {
            if(result)
                GroupTransaction.commit();
            else
                GroupTransaction.rollback();
        }
        return result;
    }

    public boolean editGroup(GroupEx GroupEx) {
        boolean result = false;
        EntityTransaction GroupTransaction = em.getTransaction();
        try {
            GroupTransaction.begin();
            GroupEx GroupX = em.find(GroupEx.class, GroupEx.getGroupId());
            GroupX.setGroupName(GroupEx.getGroupName());
            GroupX.setGroupDescription(GroupEx.getGroupDescription());
            em.persist(GroupX);
            result = true;
        } finally {
            GroupTransaction.commit();
        }
        return result;
    }

    public boolean removeGroup(GroupEx newGroup) {
        boolean result = false;
        EntityTransaction GroupTransaction = em.getTransaction();
        try{
        GroupTransaction.begin();
        GroupEx GroupEx = retrieveGroup(newGroup.getGroupId());
        em.remove(GroupEx);
        result = true;
        }finally{
            GroupTransaction.commit();
        }
        return result;
    }
    
    public Role getRole(User sourceUser,GroupEx GroupEx)
    {
        List<GroupMember> joinedGroups = sourceUser.getGroupMemberList();
        int index = joinedGroups.indexOf(new GroupMember(new GroupMemberPK(GroupEx.getGroupId(), sourceUser.getUserId())));
        if(index != -1)        
            return joinedGroups.get(index).getRole();
        return null;
    }
    
    
    public List<IGroupRole> getGroups(User sourceUser)
    {
        List<IGroupRole> joinedGroups = Converter.getGroupRoleList(sourceUser.getGroupMemberList());
        return joinedGroups;
    }
        
    
//    public boolean isInGroup(User sourceUser,GroupEx GroupEx)
//    {  
//        List<DBGroupMember> joinedGroups = sourceUser.getDBGroupMemberList();
//        boolean find = joinedGroups.contains(new GroupMember(new GroupMemberPK(GroupEx.getGroupId(), sourceUser.getUserId())));
//        return find;
//    }
    
     public GroupMember addUserToGroup(User sourceUser,GroupEx GroupEx,Role role)
    {
        GroupMember result = null;
        if(getRole(sourceUser, GroupEx) == null){
            GroupMember member = new GroupMember(new GroupMemberPK(GroupEx.getGroupId(), sourceUser.getUserId()));
            member.setRole(role);
            sourceUser.getGroupMemberList().add(member);
            result = member;
        }
        return result;
    }

    public boolean inviteUser(GroupEx GroupEx,User sourceUser,User destUser,String comment)
    {
        boolean result = false;
        EntityTransaction GroupTransaction = em.getTransaction();
        try {
            GroupTransaction.begin();
            // Check whether there are no pending inviation 
            // admin is not allowed to send more than one invitation to the same user before the user makes decision
            GroupInvitation pendingInvitation = em.createNamedQuery("DBGroupInvitation.findInvitations", GroupInvitation.class).setParameter(1, GroupEx).setParameter(2, sourceUser).setParameter(3, destUser).setParameter(4, 0).getSingleResult();
            if (pendingInvitation != null) {
                // Check whether the user is already part of the GroupEx
                if (getRole(destUser,GroupEx) == null) {
                    GroupInvitation invitation = new GroupInvitation(new GroupInvitationPK(GroupEx.getGroupId(), sourceUser.getUserId(), destUser.getUserId()));
                    invitation.setIsApproved((short) 0);
                    em.persist(invitation);
                    result = true;
                }
            }
        } finally {
            GroupTransaction.commit();
        }
        return result;
    }
         
    void acceptInvitation(GroupEx GroupEx,User retrieveUser) {
        GroupInvitation invitation = em.find(GroupInvitation.class, new GroupInvitationPK(GroupEx.getGroupId(), retrieveUser.getUserId(), 0 ));
        if(invitation != null)
        {
            invitation.setIsApproved((short)1);
            addUserToGroup(retrieveUser, GroupEx, null);
        }
    }
    
    void rejectInvitation(GroupEx GroupEx, User retrieveUser) {
        GroupInvitation invitation = em.find(GroupInvitation.class, new GroupInvitationPK(GroupEx.getGroupId(), retrieveUser.getUserId(), 0 ));
        if(invitation != null)
        {
            invitation.setIsApproved((short)2);
        }
    }
    
    GroupInvitation getInvitation(GroupEx GroupEx, User retrieveUser) {
        GroupInvitation invitation = em.find(GroupInvitation.class, new GroupInvitationPK(GroupEx.getGroupId(), retrieveUser.getUserId(), 0 ));
        return invitation;
    }

    List<IGroupRole> getGroupMember(GroupEx paramGroup) {
        GroupEx group = em.find(GroupEx.class, paramGroup.getGroupId());
        return group.getGroupMemberList();
    }
}
